package com.conceal.client.controller;
import com.conceal.client.service.ConcealWxSessionService;
import com.conceal.client.utils.SpringUtil;
import com.conceal.client.utils.StringDecoder;
import com.conceal.client.utils.StringEncoder;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;


/**
 * 微信小程序集成websocket消息订阅
 *
 */
@ServerEndpoint( value="/websocket/{sid}", decoders = StringDecoder.class,encoders = StringEncoder.class)
@Component
public class WxWebSocket {
    protected static Logger log = Logger.getLogger(WxWebSocket.class);

    ConcealWxSessionService concealWxSessionService= (ConcealWxSessionService)SpringUtil.getBean("concealWxSessionServiceImpl");

    private static final int wxa_session_timeout=1800; // 微信小程序会话超时

    private Session socket;

    private String sid;

    // 会员连接表
    static Hashtable<String, ArrayList<WxWebSocket>> users = new Hashtable<String, ArrayList<WxWebSocket>>();
    // 连接转会员id
    static Hashtable<String, String> socket2pid=new Hashtable<String, String>();

    public WxWebSocket() { }


    @OnOpen
    public void onOpen(Session socket, @PathParam("sid") String sid) throws IOException, EncodeException {
        System.out.println(sid);
        System.out.println(this);
        if(concealWxSessionService.validateSession(sid, wxa_session_timeout)) { // 微信会话合法性检测
            String pid=concealWxSessionService.getPid(sid, wxa_session_timeout);
            if(pid!=null) { // 会员号合法性检测
                this.socket = socket;
                this.sid = sid;
                // 取会员表中的会员
                ArrayList<WxWebSocket> conns=users.get(pid);
                if(conns==null) { // 没有取到
                    // 新建本会员的websocker表
                    conns=new ArrayList<WxWebSocket>();
                }
                // 添加本socket到连接表中
                conns.add(this);
                // 保存本会员的连接表
                users.put(pid, conns);
                System.out.println("====== conns.size="+conns.size());
                // 保存连接转会员id
                socket2pid.put(socket.getId(), pid);
                log.info("Pid "+pid + " has a new connection.");
            }else { // 不合法
                socket.close(); // 直接关闭
            }
        }else { // 不合法
            socket.close(); // 直接关闭
        }
    }

    /**
     * 收到客户端websocket消息
     * @param message
     * @throws IOException
     * @throws EncodeException
     */
    @OnMessage
    public void onMessage(Session socket, String message) throws IOException, EncodeException {
        System.out.println("----------消息已接受");
        System.out.println(message);
        log.info(message.toString());
        String pid = socket2pid.get(socket.getId());
        onSend(pid,message);//向客户端发送消息
        System.out.println("----------消息已发送");
    }

    /**
     * websocket客户端关闭
     * @throws IOException
     * @throws EncodeException
     */
    @OnClose
    public void onClose(Session socket) throws IOException, EncodeException {
        log.info(socket.getId() + " disconnected!");
        String pid=socket2pid.get(socket.getId());
        if(pid!=null){ // 找到会员id
            // 取会员表中的会员
            ArrayList<WxWebSocket> conns=users.get(pid);
            if(conns!=null) { // 取到连接表
                for(int i=conns.size()-1; i>=0; i--) {
                    WxWebSocket item=conns.get(i);
                    if(item.socket.getId().equals(socket.getId())) { //socketID一致
                        conns.remove(i);
                    }
                }
            }
        }
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        throwable.printStackTrace();
    }

    /**
     * 发送
     * @param toId
     * @param text
     * @throws IOException
     * @throws EncodeException
     */
    private static void send(String toId, String text) throws IOException {
        // 取接收人的连接表
        ArrayList<WxWebSocket> conns=users.get(toId);
        if(conns!=null) { // 取到连接表
            for(int i=conns.size()-1; i>=0; i--) {
                WxWebSocket item=conns.get(i);
                item.socket.getBasicRemote().sendText(text);
            }
        }
    }

    /**
     * 广播消息
     * @param text
     * @throws IOException
     */
    public static void broadcast(String text) {
        // 取接收人的连接表
        Iterator<ArrayList<WxWebSocket>> list= users.values().iterator();
        while(list.hasNext()) {
            ArrayList<WxWebSocket> conns=list.next();
            if(conns!=null) { // 取到连接表
                for(int j=conns.size()-1; j>=0; j--) {
                    WxWebSocket item=conns.get(j);
                    try {
                        item.socket.getBasicRemote().sendText(text);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }


    /**
     * 发送信息
     * @param toId
     * @param data
     */
    protected static void onSend(String toId, String data) {
        try {
            send(toId, data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
